#include <asm/uaccess.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/list_sort.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/slab.h>

#define MESSAGE_LENGTH 2048

static char Message[MESSAGE_LENGTH];

struct process_list
{
	struct task_struct task_list;
	struct list_head list;
};

static struct list_head head;

static int get_task_list(void);
static int remove_task_list(void);

static void *list_seq_start(struct seq_file * , loff_t *);
static void *list_seq_next(struct seq_file * , void * , loff_t *);
static void list_seq_stop(struct seq_file * , void *);
static int list_seq_show(struct seq_file * , void *);

int get_task_list(void)
{
	struct process_list *tail;
	struct task_struct *task_list;
	INIT_LIST_HEAD(&head);
	
	for_each_process(task_list)
	{
		tail=(struct process_list*)kmalloc(sizeof(struct process_list), GFP_KERNEL);
		tail->task_list.pid = task_list->pid;
		memcpy(tail->task_list.comm, task_list->comm, sizeof(task_list->comm));
		list_add_tail(&(tail->list), &head);
		
	}
	return 0;
}

int remove_task_list(void)
{
	struct process_list *tmp;
	struct list_head *p;
	struct list_head *p_safe;
	
	list_for_each_safe(p, p_safe, &head)
	{
		tmp = list_entry(p, struct process_list, list);
		printk("freeing item: PID [%d] TASK = %s\n", tmp->task_list.pid, tmp->task_list.comm);
		list_del(p);
		kfree (tmp);
	}
	return 0;
}

static void *list_seq_start(struct seq_file *s, loff_t *pos)
{
        if (!s->private)
                s->private = seq_list_start(&head, *pos);
        else if (s->private == &head)
                return NULL;

        return s->private;
}
static void *list_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	(*pos)++;
        s->private = ((struct list_head *)s->private)->next;

        return NULL;
}

static int list_seq_show(struct seq_file *s, void *v)
{
	struct process_list *val = NULL;
	val = list_entry((struct list_head *)v, struct process_list, list);
	return seq_printf(s, "PID: %5d   COMM: %s\n", val->task_list.pid, val->task_list.comm);
}

static void list_seq_stop(struct seq_file *s, void *v)
{
	
}
static const struct seq_operations ops = {
	.start = list_seq_start,
	.next  = list_seq_next,
	.stop  = list_seq_stop,
	.show  = list_seq_show
};

static int myopen(struct inode *inode, struct  file *file)
{
	seq_open(file, &ops);
	return 0;
}

static int mywrite(struct file *filp, const char *buff, size_t len, loff_t * off)
{
	int i;
	for (i = 0; i < MESSAGE_LENGTH - 1 && i < len; i++)
		get_user(Message[i], buff + i);
	Message[i] = '\0';
	if(!(strcmp(Message,"refresh\n")))
	{
		get_task_list();
		printk("myinit\n");
	}
	return i;
}

static struct file_operations fops={
	.owner = THIS_MODULE,	
	.read=seq_read,
	.open=myopen,
	.write=mywrite
};

int init_module(void)
{
	get_task_list();
	proc_create("snapshot", 0, NULL, &fops);
	printk("/proc/snapshot was created");
	return 0;
}

void cleanup_module(void)
{
	remove_proc_entry("snapshot", 0);
	printk("/proc/snapshot was deleted");
	remove_task_list();
}
